function Hero() {
  
  // Enums
  
  // Orientation values
  this.ORIENTATION = {};
  this.ORIENTATION.RIGHT = 0;
  this.ORIENTATION.UP = 1;
  this.ORIENTATION.DOWN = 2;
  this.ORIENTATION.LEFT = 3;
  
  // Constants
  this.HERO_SPRITES_PER_ROW = 8;
  this.HERO_SPRITES_PER_COLLUMN = 9;
    
  this.HERO_SPRITE_WIDTH = 200;
  this.HERO_SPRITE_HEIGHT = 200;
  this.HERO_SPRITE_CENTER_X = 100;
  this.HERO_SPRITE_CENTER_Y = 180;
  
  // defines the offset of the status message getDrawPosition()
  this.STATUS_OFFSET_X = -20;
  this.STATUS_OFFSET_Y = -90;
  
  this.FOOD_LOSS = 1;
  this.MAX_FOOD = 100;
 
  this.WATER_LOSS = 1;
  this.WATER_LOSS_DELAY = 30;
  this.MAX_WATER = 100;
  this.WATER_PICK_UP_DEALY = 20;
  this.WATER_PICK_UP_AMOUNT = 1; // Picking up is continuous, only sound and status has timer
 
  this.DEFAULT_MOVEMENT_SPEED = 10;
  this.START_ORIENTATION = this.ORIENTATION.DOWN;
  this.TICK_PER_ANIMATION_IMAGE = 3;
  this.NUM_ANIMATIONS = 4;
  
  // Variables
  this.orientation;
  this.velocity;
  this.position; // x: center of the hero, y: foot point (max y value of hero)
  this.target;
  this.targetTileCoords;
  
  this.food;
  this.water;
  this.points;
  this.waterTimer;
  this.waterPickUpTimer; // time till water can be picked up again
  
  this.WEAPON_RANGE = 0.8;
  this.WEAPON_USE_TIME = 7;
  this.WEAPON_REQUIRED_HITS = [1, 4, 3, 2, 1, 1];
  this.WEAPON_ANIMATION_TIME = 14;
  
  this.weapon = 0;
  this.weaponTimer = this.WEAPON_USE_TIME * 2;
  this.weaponHits = this.WEAPON_REQUIRED_HITS[this.weapon];
  this.weaponAnimation = false;
  this.weaponAnimationTimer = this.WEAPON_ANIMATION_TIME;
  
  this.hitParticles;
  
  this.statusParticles;
  this.statusIcon; // 0 = getting food, 1 = losing food, 2 = getting water, 3 = loosing water
  
  this.envelopeParts = 0;
  this.ballastSacks = 0;
  this.ropes = 0;
  this.burners = 0;
  this.baskets = 0;
  
  this.movementSpeed;
  
  this.animationTickCounter;
  this.animationStatus;
  this.movementAnimation = false;
  
  this.init = function() {
    
    this.food = this.MAX_FOOD;
    this.water = this.MAX_WATER;
    this.points = 0;
    this.waterTimer = this.WATER_LOSS_DELAY;
    this.waterPickUpTimer = 0;
    
    this.orientation = this.START_ORIENTATION;
    
    this.target = { x : 0, y : 0 };
    this.targetTileCoords = { x : 0, y : 0 };
    
    this.velocity = {};
    this.velocity.x = 0;
    this.velocity.y = 0;
    this.setToStartPosition();
    
    this.animationStatus = 0;
    this.animationTickCounter = 0;
    this.movementSpeed = this.DEFAULT_MOVEMENT_SPEED;
    this.animation = 0;
    
    this.hitParticles = new ParticleSystem();
    this.hitParticles.setMode(ParticleSystem.BURST_MODE);
    this.hitParticles.setType(1);
    this.hitParticles.setV(-0.5, 0.5, -2.0, 0.0);
    this.hitParticles.setA(-0.1, 0.1, 1.0, 1.2);
    this.hitParticles.setLife(10, 15);
    
    this.statusParticles = new ParticleSystem();
    this.statusParticles.setType(3);
    this.statusParticles.setV(0, 0, -3.5, -3.5);
    this.statusParticles.setA(0, 0, 0.5, 0.5);
    this.statusParticles.setLife(25, 25);
    this.statusParticles.setParticlesPerTick(1);
    this.statusParticles.setMode(ParticleSystem.BURST_MODE); 
  };
  
  this.restart = function() {
    this.food = this.MAX_FOOD;
    this.water = this.MAX_WATER;
    this.points = 0;
    this.weapon = 0;
    this.orientation = this.START_ORIENTATION;
    
    this.envelopeParts = 0;
    this.ballastSacks = 0;
    this.ropes = 0;
    this.burners = 0;
    this.baskets = 0;
    
  };
  
  
  this.update = function() {
    
    if (game.state == Game.INGAME_STATE) {
      this.waterTimer--;
      if(this.waterTimer <= 0) {
        this.waterTimer = this.WATER_LOSS_DELAY;
        this.water -= this.WATER_LOSS;
      }
    
      if(hero.water <= 0) {
        game.switchState(Game.GAME_OVER);
      }
    
      if(this.waterPickUpTimer-- < 0) {
        this.waterPickUpTimer--;
      }
    
      this.handleSpecialTiles(); // has to be before pickUpStuff() 
      this.pickUpStuff();
    
      this.updateAnimationStatus();
    }
    
  };

  
  // Has to be called before updating the velocity because old velocity is needed. 
  this.updateOrientation = function(direction) {
    if(direction.x > 0) {
      this.orientation = this.ORIENTATION.RIGHT;
    } else if(direction.x < 0) {
      this.orientation = this.ORIENTATION.LEFT;
    } else if(direction.y > 0) {
      this.orientation = this.ORIENTATION.DOWN;
    } else if(direction.y < 0) {
      this.orientation = this.ORIENTATION.UP;
    }
  };
  

  this.draw = function(viewPosition) {
    var currentSpriteCoords = this.getCurrentSpriteCoords();
    var imagePos = this.getDrawPosition(viewPosition);
    img.drawSprite("heroSprite", imagePos.x - this.HERO_SPRITE_CENTER_X, imagePos.y - this.HERO_SPRITE_CENTER_Y, this.HERO_SPRITE_WIDTH, this.HERO_SPRITE_HEIGHT, currentSpriteCoords.x, currentSpriteCoords.y);
  
    this.drawStatus(viewPosition);
  };
  
  
  this.drawParticles = function(viewPosition) {  
    c.save();
    c.translate(-viewPosition.x, -viewPosition.y);
    
    // Draw tree particles   
    this.hitParticles.setEmitter(this.targetTileCoords.x + rand(-22, 22), this.targetTileCoords.y + rand(-60, 5));
    this.hitParticles.draw();
    
    c.restore();
  };
 
  
  this.drawStatus = function(viewPosition) {
    // Draw status particles
    this.statusParticles.draw();
    this.statusParticles.setEmitter(this.getStatusPositon(viewPosition).x, this.getStatusPositon(viewPosition).y);
  };

  
  this.getPosition = function() {
    return this.position;
  };
   
  
  this.getPoints = function() {
    return this.points;
  };
   
  
  this.addPoints = function(newPoints){
    this.points += newPoints;
  }; 

  
  this.getCurrentTileId = function() {
    var tileCoords = this.getTileCoordinates();
    return  map.tiles[tileCoords.y][tileCoords.x];
  };

  
  this.getTileCoordinates = function() {
    return map.getTileCoordinates({ x : this.position.x, y : this.position.y});
  };
 
  
  this.getCurrentSpriteCoords = function() {
    
    if(this.weaponAnimation) {
      
      var animationX = (2 * this.weapon) - (Math.floor(2 * (this.weaponAnimationTimer - 1) / this.WEAPON_ANIMATION_TIME) + 1);
      
      if(this.orientation == this.ORIENTATION.UP) {
        currentSpriteCoords = { x : animationX, y : 4 };
         
      } else if(this.orientation == this.ORIENTATION.RIGHT) {
        currentSpriteCoords = { x : animationX, y : 5 };
         
      } else if(this.orientation == this.ORIENTATION.DOWN) {
        currentSpriteCoords = { x : animationX, y : 6 };
        
      } else if(this.orientation == this.ORIENTATION.LEFT) {
        currentSpriteCoords = { x : animationX, y : 7 };
      }
      
    } else {
      
      if(this.orientation == this.ORIENTATION.UP) {
        currentSpriteCoords = { x : this.animationStatus, y : 0 };
         
      } else if(this.orientation == this.ORIENTATION.RIGHT) {
        currentSpriteCoords = { x : this.animationStatus, y : 1 };
         
      } else if(this.orientation == this.ORIENTATION.DOWN) {
        currentSpriteCoords = { x : this.animationStatus, y : 2 };
        
      } else if(this.orientation == this.ORIENTATION.LEFT) {
        currentSpriteCoords = { x : this.animationStatus, y : 3 };
      }
      
    }
    return currentSpriteCoords;
  }; 

  
  this.getDrawPosition = function(viewPosition) {
     return { x : this.position.x - viewPosition.x, y : this.position.y - viewPosition.y };  
  };
  
  
  this.getStatusPositon = function(viewPosition){
    var dPosition = this.getDrawPosition(viewPosition);
    dPosition.x += this.STATUS_OFFSET_X;
    dPosition.y += this.STATUS_OFFSET_Y;
    
    return dPosition;
  };
  
  
  this.setToStartPosition = function() {
    this.position = map.getSpawn();
  };
  
  
  this.setStatus = function(status, duration) {
    this.statusParticles.burst();
    
    if (status == "water") {
      this.statusIcon = 2;
    }
    else if (status == "food") {
      this.statusIcon = 0;
    }
  };
  
  
  this.incrementFood = function(amount) {

    sound.play("food");
    this.setStatus("s", 1); 
    this.food += amount;

    if(this.food > this.MAX_FOOD) {
      this.food = this.MAX_FOOD;
    }
    else {
      
    }
  };
 
  
  this.incrementWater = function(amount) {
    
    this.water += amount;   

    if(this.water > this.MAX_WATER) {
      this.water = this.MAX_WATER;
    }
    else {

    }

    if( this.waterPickUpTimer <= 0) {
      this.waterPickUpTimer = this.WATER_PICK_UP_DEALY;    
      sound.play("water");
      this.setStatus("water", 1); 
    }
  }; 
  
  
  // Moves the hero into a direction.
  this.move = function(direction) {
    
    direction = normalize(direction);
    this.updateOrientation(direction);
    
    this.velocity.x = direction.x * this.movementSpeed; 
    this.velocity.y = direction.y * this.movementSpeed;
    
    var oldPosition = { x: this.position.x, y : this.position.y };
    var newPosition = { x: (this.position.x + this.velocity.x), y : (this.position.y + this.velocity.y) };

    if(map.isTilePassable(map.getTileCoordinates(newPosition))) {
      this.position.x = newPosition.x;
      this.position.y = newPosition.y;
    }
    
    this.position.x = setInRange(hero.position.x, map.GRID_SIZE, map.SIZE_PX - map.GRID_SIZE);
    this.position.y = setInRange(hero.position.y, map.GRID_SIZE, map.SIZE_PX - map.GRID_SIZE);
    
    this.movementAnimation = (this.position.x != oldPosition.x || this.position.y != oldPosition.y);
  };
   

  this.action = function(direction) {

    if(this.weapon > 0) {
      this.weaponAnimation = true;
      
      direction = normalize(direction);
      this.updateOrientation(direction);
      
      this.target = { x : this.position.x, y : this.position.y };
      
      if(this.orientation == this.ORIENTATION.RIGHT) {
        this.target.x += this.WEAPON_RANGE * map.GRID_SIZE;
        
      } else if(this.orientation == this.ORIENTATION.LEFT) {
        this.target.x -= this.WEAPON_RANGE * map.GRID_SIZE;
        
      } else if(this.orientation == this.ORIENTATION.DOWN) {
        this.target.y += this.WEAPON_RANGE * map.GRID_SIZE;
        
      } else if(this.orientation == this.ORIENTATION.UP) {
        this.target.y -= this.WEAPON_RANGE * map.GRID_SIZE;
      }
      
      var tileCoords = map.getTileCoordinates(this.target);
      
      this.targetTileCoords = { x : (tileCoords.x + 0.5) * map.GRID_SIZE, y : (tileCoords.y + 0.5) * map.GRID_SIZE };
      
      if(this.food > 0) {
        
        if(this.weaponAnimationTimer == this.WEAPON_ANIMATION_TIME){
          sound.play("whoosh");
        }
        this.weaponAnimationTimer--;
        if (this.weaponAnimationTimer <= 0) { // Reset wapon to up position
          this.weaponAnimationTimer = this.WEAPON_ANIMATION_TIME;

        }       
        
        this.hitTree(tileCoords);
      }
      else {
        notifications.show("hungry");
      }

    }
  };
  
  
  /**
  * @param treeCoords position of the tree in tile coordinates
  */
  this.hitTree = function(treeCoords) {
    var tile = map.tiles[treeCoords.y][treeCoords.x];
    if (this.food > 0 && tile >= 24 && tile <= 47) { // Check if it is tree tile
      
      // Play hit sound in half of animation time, because wapon is lowered 
      if(this.weaponAnimationTimer == Math.floor(this.WEAPON_ANIMATION_TIME / 2)) {
        if (this.weapon > 0 && this.weapon < 4) { // wapon is knife axe or machete
          sound.play("axeChop");
        } else if(this.weapon == 4) {//chainsaw
          sound.play("chainsaw");
        }
      }
      
      if(this.weaponAnimationTimer % config.TICKS_PER_PARTICLE_BURST[this.weapon] == 0) {
        this.hitParticles.setParticlesPerTick(config.PARTICLES_PER_TICK[this.weapon]);
        this.hitParticles.burst();
      }

      if(this.weapon == 5) {
        this.weaponTimer = 1;
      }
      if(tile >= 40 && tile <= 47) {
        this.weaponTimer--;
        this.hitParticles.setType(2);
      } else {
        this.weaponTimer -= 2;
        this.hitParticles.setType(1);
      }
      
      if(this.weaponTimer <= 0) {
        
        this.food--;
        if(this.food < 0) {
          this.food = 0;
        }
        
        this.weaponTimer = this.WEAPON_USE_TIME * 2;
        this.weaponHits--;
        if (this.weaponHits <= 0) {
                     
          this.weaponHits = this.WEAPON_REQUIRED_HITS[this.weapon];
          tile++;
          if(tile % 4 != 0) {
            map.tiles[treeCoords.y][treeCoords.x] = tile;
          } else {
            map.tiles[treeCoords.y][treeCoords.x] = 0;
            if(tile > 40 ) {
              map.lightenTile(treeCoords);
            } 
          }            
        }
      }
    }
  };


  this.updateAnimationStatus = function() {

  if(this.movementAnimation) {
    this.animationTickCounter += 1;

  if(this.animationTickCounter >= this.TICK_PER_ANIMATION_IMAGE) {
    this.animationStatus += 1;
    this.animationStatus = this.animationStatus % this.NUM_ANIMATIONS;
    this.animationTickCounter = 0;
  }

  } else {
    this.animationStatus = 0;
    this.animationTickCounter = this.TICK_PER_ANIMATION_IMAGE - 1;
  }

  };


  this.resetWeaponTimer = function() {
    this.weaponTimer = this.WEAPON_USE_TIME * 2;
    this.weaponHits = this.WEAPON_REQUIRED_HITS[this.weapon];
    this.weaponAnimation = false;
    this.weaponAnimationTimer = this.WEAPON_ANIMATION_TIME;
  }
 

  this.handleSpecialTiles = function() {
    var tile = this.getCurrentTileId();

    // Handle water

    if(tile >= config.WATER_MIN_ID && tile <= config.WATER_MAX_ID) {       
      this.incrementWater(this.WATER_PICK_UP_AMOUNT);
    }

    if( tile == config.YIGGDRASIL_TILE_ID || (game.levelNum == config.NUM_LEVELS && tile == config.BASKET_TILE_ID)) {
      game.completeLevel(); 
    }
  };
  
   
   this.pickUpStuff = function() {

     var tileCoords = map.getTileCoordinates({ x : this.position.x, y : this.position.y});
     var tile = map.tiles[tileCoords.y][tileCoords.x];
    
     // Handle food
     if(tile == config.APPLE_TILE_ID) {
       this.incrementFood(config.FOOD_FROM_APPLE);
       map.tiles[tileCoords.y][tileCoords.x] = 0;
       this.addPoints(config.POINTS_FROM_APPLE); 
     }
     if(tile == config.BANANA_TILE_ID) {
       this.incrementFood(config.FOOD_FROM_BANANA);
       map.tiles[tileCoords.y][tileCoords.x] = 1;
       this.addPoints(config.POINTS_FROM_APPLE);
     }
     if(tile == config.BREAD_TILE_ID) {
       this.incrementFood(config.FOOD_FROM_BANANA);
       map.tiles[tileCoords.y][tileCoords.x] = 2;
       this.addPoints(config.POINTS_FROM_APPLE);
     }
     if(tile == config.MEAT_TILE_ID) {
       this.incrementFood(config.FOOD_FROM_BANANA);
       map.tiles[tileCoords.y][tileCoords.x] = 3;
       this.addPoints(config.POINTS_FROM_APPLE);
     }
     if(tile == config.RICE_TILE_ID) {
       this.incrementFood(config.FOOD_FROM_RICE);
       map.tiles[tileCoords.y][tileCoords.x] = 4;
       this.addPoints(config.POINTS_FROM_APPLE);
     }
    
     // Handle balloon parts
     if(tile == config.ENVELOPE_PART_TILE_ID) {
       this.envelopeParts++;
       this.envelopeParts = Math.min(this.envelopeParts, config.REQUIRED_ENVELOPE_PARTS);
       map.tiles[tileCoords.y][tileCoords.x] = 0;
       this.addPoints(config.POINTS_FROM_ENVELOPE_PART);
       sound.play("pickUpBalloonPiece");
     }
     if(tile == config.ROPE_TILE_ID) {
       this.ropes++;
       this.ropes = Math.min(this.ropes, config.REQUIRED_ROPES);
       map.tiles[tileCoords.y][tileCoords.x] = 1;
       this.addPoints(config.POINTS_FROM_ROPE);
       sound.play("pickUpBalloonPiece");
     }
     if(tile == config.BALLAST_SACK_TILE_ID) {
       this.ballastSacks++;
       this.ballastSacks = Math.min(this.ballastSacks, config.REQUIRED_BALLAST_SACKS);
       map.tiles[tileCoords.y][tileCoords.x] = 2;
       this.addPoints(config.POINTS_FROM_BALLAST_SACK);
       sound.play("pickUpBalloonPiece");
     }
     if(tile == config.BURNER_TILE_ID) {
       this.burners++;
       this.burners = Math.min(this.burners, config.REQUIRED_BURNERS);
       map.tiles[tileCoords.y][tileCoords.x] = 3;
       this.addPoints(config.POINTS_FROM_BURNER);
       sound.play("pickUpBalloonPiece");
     }
     if(tile == config.BASKET_TILE_ID) {
       this.baskets++;
       this.baskets = Math.min(this.baskets, config.REQUIRED_BASKETS);
       map.tiles[tileCoords.y][tileCoords.x] = 4;
       this.addPoints(config.POINTS_FROM_BASKET);
       sound.play("pickUpBalloonPiece");
     }
    
     // Handle weapon 
     if(tile == config.KNIFE_TILE_ID) {
       notifications.show("knife");
       if(this.weapon < 1) {
         this.weapon = 1;
       }
       map.tiles[tileCoords.y][tileCoords.x] = 0; 
       this.addPoints(config.POINTS_FROM_KINFE);
       sound.play("pickUpMachete");
     }
     if(tile == config.MACHETE_TILE_ID) {
       notifications.show("machete");
       if(this.weapon < 2) {
         this.weapon = 2;
         sound.play("pickUpMachete");
       }
       map.tiles[tileCoords.y][tileCoords.x] = 1;
       this.addPoints(config.POINTS_FROM_MACHETE);
       sound.play("pickUpMachete");
     }
     if(tile == config.AXE_TILE_ID) {
       notifications.show("axe");
       if(this.weapon < 3) {
         this.weapon = 3;
       }
       map.tiles[tileCoords.y][tileCoords.x] = 2;
       this.addPoints(config.POINTS_FROM_AXE);
       sound.play("pickUpMachete");
     }
     if(tile == config.CHAINSAW_TILE_ID) {
       notifications.show("chainsaw");
       if(this.weapon < 4) {
         this.weapon = 4;
       }
       map.tiles[tileCoords.y][tileCoords.x] = 3;
       this.addPoints(config.POINTS_FROM_CHAINSAW);
       sound.play("startingChainsaw");
     }
   };  
}